package com.jmb.api.web.core.http;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.jmb.api.common.exception.ParseException;
import com.jmb.api.common.exception.ValidUtilException;
import com.jmb.api.common.result.RelyType;
import com.jmb.api.common.utils.*;
import com.jmb.api.entity.*;
import com.jmb.api.vo.Interface.Assert.InterfaceAssertVO;
import com.jmb.api.vo.Interface.Case.Execute.InterfaceCaseExecuteLogVO;
import com.jmb.api.vo.Interface.Case.InterfaceCaseInfoVO;
import com.jmb.api.vo.Interface.Case.Suite.InterfaceCaseSuiteVO;
import com.jmb.api.web.core.Node;
import com.jmb.api.web.core.parser.Parser;
import com.jmb.api.web.env.Env;
import com.jmb.api.web.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.ResourceAccessException;

import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.*;

@Slf4j
@Component
public class

ExecuteHandler implements Node {
    @Autowired
    private InterfaceCaseService interfaceCaseService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ProjectService projectService;
    @Autowired
    private Env env;
    @Autowired
    private InterfaceCaseSuiteService ifSuiteService;
    @Autowired
    private InterfacePreCaseService interfacePreCaseService;
    @Autowired
    private InterfaceCaseExecuteLogService interfaceCaseExecuteLogService;
    @Autowired
    private Parser parser;
    @Autowired
    private Request request;
    @Autowired
    private InterfaceAssertLogService assertLogService;
    @Autowired
    private InterfaceProcessorLogService interfaceProcessorLogService;
    @Autowired
    private InterfaceCaseExecuteLogService logService;

    public Long executeInterfaceCase(ExecuteInterfaceCaseParam executeInterfaceCaseParam){
        // 获取用例信息
        long methodStart = TimeUtil.now();

        Long interfaceCaseId = executeInterfaceCaseParam.getInterfaceCaseId();
        String executor = executeInterfaceCaseParam.getExecutor();
        String suiteLogNo = executeInterfaceCaseParam.getSuiteLogNo();
        String chainNo = executeInterfaceCaseParam.getChainNo();
        Long suiteId = executeInterfaceCaseParam.getSuiteId();
        Integer isFailedRetry = executeInterfaceCaseParam.getIsFailedRetry();
        String suiteLogDetailNo = executeInterfaceCaseParam.getSuiteLogDetailNo();
        // 初始化全局变量，防止空指针
        HashMap globalHeaders = Optional.ofNullable(executeInterfaceCaseParam.getGlobalHeaders()).orElse(new HashMap<>());
        HashMap globalParams = Optional.ofNullable(executeInterfaceCaseParam.getGlobalParams()).orElse(new HashMap<>());
        HashMap globalData = Optional.ofNullable(executeInterfaceCaseParam.getGlobalData()).orElse(new HashMap<>());

        Integer source = executeInterfaceCaseParam.getSource();
        String casePreNo = executeInterfaceCaseParam.getCasePreNo();
        Boolean skipPreCase = executeInterfaceCaseParam.getSkipPreCase();

        InterfaceCaseInfoVO interfaceCaseInfoVO = interfaceCaseService.findInterfaceCaseById(interfaceCaseId);
        if (interfaceCaseInfoVO ==  null){
            log.error("用例不存在");
            throw new ValidUtilException("用例不存在");
        }
        String description = interfaceCaseInfoVO.getDescription();
        Long projectId = interfaceCaseInfoVO.getProjectId();

        String exceptionMessage = null; // 接受异常信息
        Integer caseStatus = 0; // 运行结果，0-成功，1-失败
        String url;
        String requestBody = null; // 记录请求日志requestBody字段
        // source 来源（0用例调试 1依赖调试 2运行整个测试套件 3测试套件单个用例调试 4依赖解析 5综合用例-前置用例）
        RelyType startRelyType;
        RelyType endRelyType;
        switch (source){
            case 1:
            case 4:
                startRelyType = RelyType.RELY_START;
                endRelyType = RelyType.RELY_END;
                break;
            case 5:
                startRelyType = RelyType.PRE_CASE_START;
                endRelyType = RelyType.PRE_CASE_END;
                break;
            default:
                startRelyType = RelyType.CASE_START;
                endRelyType = RelyType.CASE_END;
                break;

        }
        log.info("-------------------开始执行用例：{} -----------------------",interfaceCaseInfoVO.getCaseId());
        redisUtil.stackPush(chainNo,chainNode(startRelyType,null,description,null,TimeUtil.now()-methodStart,null));
        if (projectId !=null){
            // 判定运行环境
            Project project = projectService.getById(projectId);
            if (suiteId == null){ //没suiteId 使用调试环境
                url = env.domain(project,4)+interfaceCaseInfoVO.getUrl();
            }else { // 根据suiteId使用运行环境
                InterfaceCaseSuiteVO suiteVO = ifSuiteService.findInterfaceCaseSuiteById(suiteId);
                url = env.domain(project,suiteVO.getRunDev())+interfaceCaseInfoVO.getUrl();
            }
        }else {
            //  如果没有projectId，则不使用host port protocol 拼接
            url = interfaceCaseInfoVO.getUrl();
        }

        // 过滤未启用的属性
        String headers = kvCast(interfaceCaseInfoVO.getHeaders());
        String params = kvCast(interfaceCaseInfoVO.getParams());
        String formData = kvCast(interfaceCaseInfoVO.getFormData());
        String formDataEncoded = kvCast(interfaceCaseInfoVO.getFormDataEncoded());
        String raw = kvCast(interfaceCaseInfoVO.getRaw());
        String rawType = interfaceCaseInfoVO.getRawType();
        Integer bodyType = interfaceCaseInfoVO.getBodyType();
        Integer method = interfaceCaseInfoVO.getMethod();


        // 兼容header、param、form、formEncoded
        String rawHeaders = headers;
        // 兼容header、param
        String rawParams = params;

        // 确定日志记录最终记录的rawBody
        String rawBody = this.logRawBody(bodyType, formData, formDataEncoded, raw);
        // 初始化时间
        long runTime = 0;
        // 执行前置用例
        if (!skipPreCase){
            List<InterfacePreCase> preCaseList = interfacePreCaseService.findInterfacePreCaseByParentId(interfaceCaseId);
            if (!preCaseList.isEmpty()){
                String no = NoUtil.genCasePreNo();
                casePreNo = no; // 重置casePreNo
                for (InterfacePreCase preCase : preCaseList){
                    Long preCaseId = preCase.getPreCaseId();
                    log.info("开始执行前置用例：{}",preCaseId);
                    executeInterfaceCaseParam.setSource(5);
                    executeInterfaceCaseParam.setCasePreNo(no);
                    executeInterfaceCaseParam.setExecutor("前置用例");
                    executeInterfaceCaseParam.setSuiteLogNo(null); // 把前置用例作为中间依赖case处理
                    executeInterfaceCaseParam.setInterfaceCaseId(preCaseId);
                    executeInterfaceCaseParam.setSkipPreCase(true); // 当用例作为前置用例执行时，应该跳过前置用例的前置用例，仅执行自身
                    // 执行前置用例
                    Long logId = this.executeInterfaceCase(executeInterfaceCaseParam);
                    // 查询用例执行状态
                    InterfaceCaseExecuteLogVO logg = interfaceCaseExecuteLogService.findExecute(Long.valueOf(logId));
                    String caseDesc = logg.getCaseDesc();
                    Integer status = logg.getStatus();
                    if (status !=0){
                        if (status == 1){
                            exceptionMessage = String.format("前置用例 [%s] [%s]执行失败：%s 其他用例停止执行", interfaceCaseId, caseDesc);
                        }else {
                            exceptionMessage = String.format("前置用例 [%s] [%s]执行错误，错误日志[%s]：%s 其他用例停止执行", interfaceCaseId, caseDesc,logg.getErrorMessage());
                        }
                        //
                        caseStatus =2;
                        log.error(exceptionMessage);
                        break; // 终止循环，其他前置用例就不执行
                    }
                    log.info("执行结束时的 前置案例 id {}", preCaseId);
                }
            }
        }
        // 当前置用例执行不成功，记录日志并停止后续流程
        if (caseStatus == 2){
            log.error(exceptionMessage);
            return this.onRequestError(interfaceCaseId,url,description,method,null,null,null,
                    rawHeaders,rawParams,rawBody,executor,exceptionMessage,runTime,suiteLogNo,suiteLogDetailNo,isFailedRetry,source,
                    rawType,bodyType,chainNo);
        }
        // 发送请求
        ResponseEntity responseEntity = null;
        HashMap headersMap = null;
        HashMap paramsMap = null;
        HashMap formDataMap;
        HashMap formDataEncodedMap;
        try {
            // 解析headers中的依赖
            headers = parser.parseDependency(headers,chainNo,suiteId,isFailedRetry,suiteLogDetailNo,globalHeaders,globalParams,globalData,casePreNo);
            // 解析params中的依赖
            params = parser.parseDependency(params,chainNo,suiteId,isFailedRetry,suiteLogDetailNo,globalHeaders,globalParams,globalData,casePreNo);
            if(bodyType == 0){
                // 解析formData中的依赖
                formData = parser.parseDependency(formData,chainNo,suiteId,isFailedRetry,suiteLogDetailNo,globalHeaders,globalParams,globalData,casePreNo);
            }else if (bodyType == 1){
                // 解析 x-www-form-encoded 中的依赖
                formDataEncoded = parser.parseDependency(formDataEncoded,chainNo,suiteId,isFailedRetry,suiteLogDetailNo,globalHeaders,globalParams,globalData,casePreNo);
            }else if (bodyType == 2){
                // 解析 raw 中的依赖
                raw = parser.parseDependency(raw,chainNo,suiteId,isFailedRetry,suiteLogDetailNo,globalHeaders,globalParams,globalData,casePreNo);
            }else if (bodyType == 9){
                log.info("bodyType为空，不解析依赖项");
            }else {
                log.error("不支持的 bodyType");
                throw new ParseException("不支持的 bodyType");
            }
            // 合并公共headers
            headersMap = this.mergeSuiteProperty(globalHeaders,headers);
            // 合并公共params
            paramsMap = this.mergeSuiteProperty(globalParams,params);
            // 合并公共 formDataEncoded
            formDataEncodedMap = this.mergeSuiteProperty(globalData,formDataEncoded);
            // 兼容formData不合并
            formDataMap = JSONObject.parseObject(formData, HashMap.class);

            // 处理URL参数
            HashMap<String,Object> urlParamsWrapper = Request.pathVariableParser(url, paramsMap);
            url = (String) urlParamsWrapper.get("url");
            paramsMap = (HashMap<String, String>) urlParamsWrapper.get("params");

            // 确定日志记录最终记录的requestBody
            requestBody = this.logRequestBody(bodyType,formDataMap,formDataEncodedMap,raw);
            // 确定请求方式
            HttpMethod httpMethod =this.httpMethod(method);
            // 发送请求
            long startTime = System.currentTimeMillis();
            responseEntity = this.doRequest(bodyType, httpMethod, url, headersMap, paramsMap, formDataMap, formDataEncodedMap, raw, rawType);
            runTime = System.currentTimeMillis() - startTime;
            log.info("请求耗时：{}ms",runTime);
        }catch (ResourceAccessException e){
            caseStatus =2;
            log.error("连接超时，尝试检查超时设置和代理服务器, {}",e.getMessage());
            exceptionMessage = "连接超时，尝试检查超时设置和代理服务器";
        }
        catch (Exception e){
            caseStatus = 2 ;
            log.error("请求异常：{}",e.getMessage());
            exceptionMessage = "请求异常：" + e.getMessage();
        }
        int responseCode;
        String responseHeaders;
        String responseBody;

        if (responseEntity == null){
            // 请求失败
            return this.onRequestError(interfaceCaseId, url, description, method, headersMap, paramsMap, requestBody,
                    rawHeaders, rawParams, rawBody, executor, exceptionMessage, runTime,
                    suiteLogNo, suiteLogDetailNo, isFailedRetry, source, rawType, bodyType, chainNo);
        }else {
            // 请求成功
            responseCode = Request.code(responseEntity);
            responseHeaders = Request.headersPretty(responseEntity);
            responseBody = Request.body(responseEntity);
            // 记录请求日志
            Long executedLogId = this.onRequestSuccess(responseCode, responseHeaders, responseBody,
                    interfaceCaseId, url, description, method, headersMap, paramsMap, requestBody,
                    rawHeaders, rawParams, rawBody, runTime, executor, suiteLogNo, suiteLogDetailNo,
                    isFailedRetry, source, rawType, bodyType, caseStatus);
            // 请求参数缓存
            this.cacheRequest(interfaceCaseInfoVO.getPostProcessors(),executedLogId,headers,params,formDataEncoded,raw,
                    casePreNo,suiteLogDetailNo,chainNo);
            // 执行断言
            List<InterfaceAssertVO> asserts = interfaceCaseInfoVO.getAsserts();
            Integer statusAfterAssert = this.doAssert(asserts, interfaceCaseId, executedLogId, responseCode, responseHeaders, responseBody, runTime, chainNo,
                    suiteId, isFailedRetry, suiteLogDetailNo, casePreNo, globalHeaders, globalParams, globalData);
            // 响应数据缓存
            this.cacheResponse(interfaceCaseInfoVO.getPostProcessors(), interfaceCaseId, executedLogId,
                    statusAfterAssert, responseHeaders, responseBody,
                    casePreNo, suiteLogDetailNo, chainNo);
            // 写入redis，写入日志 手动写入，否则前置用例的跟踪链看不到
            redisUtil.stackPush(chainNo,chainNode(endRelyType,executedLogId,interfaceCaseInfoVO.getDescription(),null
            ,TimeUtil.now()-methodStart,null));
            InterfaceCaseExecuteLog modifyChain = new InterfaceCaseExecuteLog();
            modifyChain.setId(executedLogId);
            modifyChain.setChain(JSON.toJSONString(redisUtil.stackGetAll(chainNo)));
            logService.modifyExecuteLog(modifyChain);
            // 返回日志编号
            return executedLogId;
        }

    }

    /**
     * 发送http请求
     * @param bodyType bodyType
     * @param methodEnum 请求方式枚举
     * @param url 请求url
     * @param headersMap headersMap
     * @param paramsMap paramsMap
     * @param formDataMap formDataMap
     * @param formDataEncodedMap formDataEncodedMap
     * @param raw raw
     * @param rawType raw类型
     * @return ResponseEntity
     */
    public ResponseEntity doRequest(Integer bodyType, HttpMethod methodEnum,
                                    String url, HashMap headersMap, HashMap paramsMap,
                                    HashMap formDataMap, HashMap formDataEncodedMap,
                                    String raw, String rawType)  {
        if (bodyType == 0) { //form-data
            return Request.requestPro(methodEnum, url, headersMap, paramsMap, formDataMap, MediaType.MULTIPART_FORM_DATA);
        } else if (bodyType == 1) { //x-www-form-encoded
            return Request.requestPro(methodEnum, url, headersMap, paramsMap, formDataEncodedMap, MediaType.APPLICATION_FORM_URLENCODED);
        } else if (bodyType == 2) { //raw
            if ("Text".equalsIgnoreCase(rawType)) {
                return Request.requestPro(methodEnum, url, headersMap, paramsMap, raw, MediaType.TEXT_PLAIN);
            } else if ("JSON".equalsIgnoreCase(rawType)) {
                return Request.requestPro(methodEnum, url, headersMap, paramsMap, raw, MediaType.APPLICATION_JSON);
            } else if ("HTML".equalsIgnoreCase(rawType)) {
                return Request.requestPro(methodEnum, url, headersMap, paramsMap, raw, MediaType.TEXT_HTML);
            } else if ("XML".equalsIgnoreCase(rawType)) {
                return Request.requestPro(methodEnum, url, headersMap, paramsMap, raw, MediaType.APPLICATION_XML);
            } else {
                throw new ValidUtilException("不支持rawType");
            }
        } else if (bodyType == 9) { //none
            return Request.requestPro(methodEnum, url, headersMap, paramsMap, null);
        } else {
            throw new ValidUtilException("不支持 bodyType");
        }
    }

    /**
     * 用例请求成功时触发（此时还未执行断言）
     * @param responseCode 响应状态码
     * @param responseHeaders 响应头
     * @param responseBody 响应体
     * @param interfaceCaseId 接口测试用例编号
     * @param url 请求URL
     * @param desc 描述
     * @param method 请求方式
     * @param headersMap 请求headers
     * @param paramsMap 请求params
     * @param requestBody 请求body
     * @param rawHeaders 未解析依赖前的headers
     * @param rawParams 未解析依赖前的params
     * @param rawBody 未解析依赖前的body
     * @param runTime 执行耗时
     * @param executor 执行人
     * @param suiteLogNo 测试套件日志编号 主要为调用入口为测试套件时使用，否则传参null
     * @param suiteLogDetailNo suiteLogNo仅记录重跑和真正运行的，suiteLogDetailNo会包括用例所依赖的case
     * @param isFailedRetry 是否为失败重跑的请求 0是1否
     * @param source 来源（0用例调试 1依赖调试 2运行整个测试套件 3测试套件单个用例调试 4依赖解析 5综合用例-前置用例）
     * @param rawType raw类型 "Text" "JSON" "HTML" "XML"
     * @param bodyType 请求体类型0form-data 1x-www-form-Encoded 2raw 9none
     * @param caseStatus 日志执行状态
     * @return 日志编号
     */
    private Long onRequestSuccess(Integer responseCode, String responseHeaders, String responseBody,
                                     Long interfaceCaseId, String url, String desc, Integer method,
                                     HashMap headersMap, HashMap paramsMap, String requestBody,
                                     String rawHeaders, String rawParams, String rawBody,
                                     Long runTime, String executor, String suiteLogNo, String suiteLogDetailNo,
                                     Integer isFailedRetry, Integer source, String rawType, Integer bodyType, Integer caseStatus) {
        String temp = responseBody;
        if (!temp.equals("")) {
            try {
                JSONObject responseBodyObject = JSONObject.parseObject(temp);
                responseBody = JSON.toJSONString(responseBodyObject, JSONWriter.Feature.PrettyFormat, JSONWriter.Feature.WriteMapNullValue);
            } catch (Exception e) {
                responseBody = temp;
            }
        }
        InterfaceCaseExecuteLog executeLogDO = new InterfaceCaseExecuteLog();
        executeLogDO.setCaseId(interfaceCaseId);
        executeLogDO.setCaseDesc(desc);
        executeLogDO.setCaseMethod(method);
        executeLogDO.setRequestHeaders(JSON.toJSONString(headersMap, JSONWriter.Feature.PrettyFormat).equals("null") ? "" : JSON.toJSONString(headersMap, JSONWriter.Feature.PrettyFormat));
        executeLogDO.setRequestParams(JSON.toJSONString(paramsMap, JSONWriter.Feature.PrettyFormat).equals("null") ? "" : JSON.toJSONString(paramsMap, JSONWriter.Feature.PrettyFormat));
        executeLogDO.setRequestBody(requestBody);
        executeLogDO.setRawRequestHeaders(rawHeaders);
        executeLogDO.setRawRequestParams(rawParams);
        executeLogDO.setRawRequestBody(rawBody);
        executeLogDO.setResponseCode(responseCode);
        executeLogDO.setResponseHeaders(responseHeaders);
        executeLogDO.setResponseBody(responseBody);
        executeLogDO.setRunTime(runTime);
        executeLogDO.setExecuter(executor);
        executeLogDO.setStatus(caseStatus);
        executeLogDO.setCreatedTime(new Date());
        executeLogDO.setCaseUrl(url);
        executeLogDO.setSuiteLogNo(suiteLogNo);
        executeLogDO.setSuiteLogDetailNo(suiteLogDetailNo);
        executeLogDO.setIsFailedRetry(isFailedRetry);
        executeLogDO.setSource(source);
        executeLogDO.setRawType(rawType);
        executeLogDO.setBodyType(bodyType);
        InterfaceCaseExecuteLog executedLogDO = interfaceCaseExecuteLogService.saveExecuteLog(executeLogDO);
        Long logId = executedLogDO.getId();
        log.info("case [{}] execution success, executeLog={}, executeLogId={}", interfaceCaseId, executedLogDO, logId);
        return logId;
    }

    // 请求缓存
    private void cacheRequest(List<InterfaceProcessor> processorList,Long executeLogId,String headers,String params,String formDataEncoded,
                              String raw,String casePreNo,String suiteLogDetailNo,String chainNo){
        // 查询用例的请求参数
        InterfaceProcessorLog interfaceProcessorLog;
        String value = null; // 缓存值
        if (!processorList.isEmpty()){
            for (InterfaceProcessor processor : processorList){
                Integer type = processor.getType();
                String expression = processor.getExpression();
                String name = processor.getName();
                Integer haveDefaultValue = processor.getHaveDefaultValue();
                String defaultValue = processor.getDefaultValue();
                Long caseId = processor.getCaseId();
                Integer isDefaultValue = null;
                // 状态 0通过 1失败
                Integer status = 0;
                // 错误日志
                String errorMsg = "";
                boolean isThrowException = false;
                String exceptionMsg = "";
                if (type >=3 && type <=6){
                    // 3request-header/4request-params/5request-data/6request-json
                    String s = "[]";
                    try {
                        switch (type){
                            case 3:
                                s = ParseUtil.parseJson(headers, expression);
                                break;
                            case 4:
                                s = ParseUtil.parseJson(params, expression);
                                break;
                            case 5:
                                s = ParseUtil.parseJson(formDataEncoded, expression);
                                break;
                            case 6:
                                s = ParseUtil.parseJson(raw, expression);
                                break;
                        }

                    }catch (ParseException e){
                        isThrowException = true;
                        exceptionMsg = e.getMessage();
                        errorMsg = "请求参数解析错误";
                    }
                    ArrayList jsonPathArray = JSONObject.parseObject(s, ArrayList.class);
                    if (jsonPathArray.isEmpty()){
                        if (haveDefaultValue == 0){
                            isDefaultValue = 0;
                            value = defaultValue;
                        }else {
                            status = 1;
                            errorMsg = String.format("请求缓存错误，json-路径提取内容为空，expression [%s]，processor =[%s]，case=[%s]"
                                    , expression,name,caseId);
                            log.error(errorMsg);
                        }
                    }else {
                        isDefaultValue = 1;
                        if (jsonPathArray.size() == 1){
                            Object o = jsonPathArray.get(0);
                            value = o == null ? null : o.toString();
                        } else {
                            value = JSON.toJSONString(jsonPathArray);
                        }
                    }
                    interfaceProcessorLog = new InterfaceProcessorLog();
                    interfaceProcessorLog.setProcessorId(processor.getId());
                    interfaceProcessorLog.setCaseId(processor.getCaseId());
                    interfaceProcessorLog.setCaseExecuteLogId(executeLogId);
                    interfaceProcessorLog.setName(name);
                    interfaceProcessorLog.setType(type);
                    interfaceProcessorLog.setExpression(expression);
                    interfaceProcessorLog.setWr(1);
                    if (!isThrowException){
                        interfaceProcessorLog.setIsDefaultValue(isDefaultValue);
                        interfaceProcessorLog.setValue(value);
                        interfaceProcessorLog.setCreatedTime(new Date());
                        interfaceProcessorLog.setStatus(status);
                        if (status == 0){
                            interfaceProcessorLog.setErrorMsg(null);
                        }else {
                            interfaceProcessorLog.setErrorMsg(errorMsg);
                        }
                        long start = TimeUtil.now();
                        interfaceProcessorLogService.saveInterfaceProcessorLog(interfaceProcessorLog);
                        // type=3request-header/4request-params/5request-data/6request-json的处理器
                        RelyType relyType;
                        if (type == 3) {
                            relyType = RelyType.WRITE_PROCESSOR_REQUEST_HEADER;
                        } else if (type == 4) {
                            relyType = RelyType.WRITE_PROCESSOR_REQUEST_PARAMS;
                        } else if (type == 5) {
                            relyType = RelyType.WRITE_PROCESSOR_REQUEST_DATA;
                        } else {
                            relyType = RelyType.WRITE_PROCESSOR_REQUEST_JSON;
                        }
                        if (status == 1) {
                            InterfaceCaseExecuteLog afterPostProcessorLogDo = new InterfaceCaseExecuteLog();
                            afterPostProcessorLogDo.setId(executeLogId);
                            afterPostProcessorLogDo.setStatus(2);
                            afterPostProcessorLogDo.setErrorMessage(errorMsg);
                            logService.modifyExecuteLog(afterPostProcessorLogDo);
                            log.info("处理器运行错误，主动将用例执行状态置为错误");
                            throw new ValidUtilException(errorMsg);
                        } else {
                            if (casePreNo != null) { //如果为前置用例，仅写入前置用例域，
                                redisUtil.hashPut(casePreNo, name, value);
                                log.info("写入处理器-前置用例域，key={}，hashKey={}，value={}", casePreNo, name, value);
                            } else {
                                if (suiteLogDetailNo == null) { // 不存在则写入临时域
                                    redisUtil.hashPut(NoUtil.TEMP_POST_PROCESSOR_NO, name, value);
                                    log.info("写入处理器-临时域，key={}，hashKey={}，value={}", NoUtil.TEMP_POST_PROCESSOR_NO, name, value);
                                } else { // 否则写入测试套件域
                                    redisUtil.hashPut(suiteLogDetailNo, name, value, 24*60*60);
                                    log.info("写入处理器-测试套件域，key={}，hashKey={}，value={}", suiteLogDetailNo, name, value);
                                }
                            }
                        }
                        redisUtil.stackPush(chainNo, chainNode(relyType, null, name, value, TimeUtil.now()-start, expression));
                        // 手动写入，否则前置用例的跟踪链看不到
                        InterfaceCaseExecuteLog modifyChain = new InterfaceCaseExecuteLog();
                        modifyChain.setId(executeLogId);
                        modifyChain.setChain(JSON.toJSONString(redisUtil.stackGetAll(chainNo)));
                        logService.modifyExecuteLog(modifyChain);
                    } else { // 若解析json、xpath出错
                        // 写入处理器记录表
                        interfaceProcessorLog.setIsDefaultValue(null);
                        interfaceProcessorLog.setValue(null);
                        interfaceProcessorLog.setCreatedTime(new Date());
                        interfaceProcessorLog.setStatus(1);
                        interfaceProcessorLog.setErrorMsg(exceptionMsg);
                        interfaceProcessorLogService.saveInterfaceProcessorLog(interfaceProcessorLog);
                        log.error("处理器解析出错，写入处理器记录表");
                        // 重置用例状态
                        InterfaceCaseExecuteLog afterPostProcessorLogDo = new InterfaceCaseExecuteLog();
                        afterPostProcessorLogDo.setId(executeLogId);
                        afterPostProcessorLogDo.setStatus( 2);
                        afterPostProcessorLogDo.setErrorMessage(exceptionMsg);
                        logService.modifyExecuteLog(afterPostProcessorLogDo);
                        log.error("处理器解析出错，主动将用例执行状态置为错误");
                        throw new ValidUtilException(errorMsg);
                    }
                }
            }
        }
    }

    /**
     * 缓存响应数据
     * @param processorList 处理器列表
     * @param interfaceCaseId 测试用例编号
     * @param executedLogId 此次执行日志编号
     * @param statusAfterAssert 断言处理后的执行日志状态
     * @param responseHeaders 响应头
     * @param responseBody 响应体
     * @param casePreNo 前置用例的参数缓存用的key，为了防止异步执行用例时，tempPostProcessor key被覆盖， 仅前置用例执行时，需要该参数
     * @param suiteLogDetailNo suiteLogNo仅记录重跑和真正运行的，suiteLogDetailNo会包括用例所依赖的case
     * @param chainNo 调用链路跟踪 将调用链信息序列
     */
    private void cacheResponse(List<InterfaceProcessor> processorList, Long interfaceCaseId, Long executedLogId,
                               Integer statusAfterAssert, String responseHeaders, String responseBody,
                               String casePreNo, String suiteLogDetailNo, String chainNo) {
        if (statusAfterAssert.intValue() == 0 ) { // *仅用例执行通过才写入处理器记录

            InterfaceProcessorLog interfaceProcessorLog;
            String value = null;

            if (!processorList.isEmpty()) {
                for(InterfaceProcessor processorDO : processorList) {
                    Integer type = processorDO.getType();
                    String expression = processorDO.getExpression();
                    String name = processorDO.getName();
                    Integer haveDefaultValue = processorDO.getHaveDefaultValue();
                    String defaultValue = processorDO.getDefaultValue();
                    Integer isDefaultValue = null;
                    Integer status = 0; // 状态 0通过 1失败
                    String errorMsg = "";
                    boolean isThrowException = false;
                    String exceptionMsg = "";
                    if (type == 0 ) { // json
                        String s = "[]";
                        try {
                            s = ParseUtil.parseJson(responseBody, expression);
                        } catch (ParseException e) {
                            isThrowException = true;
                            exceptionMsg = e.getMessage();
                        }
                        ArrayList jsonPathArray = JSONObject.parseObject(s, ArrayList.class);
                        if (jsonPathArray.isEmpty()) {
                            if (haveDefaultValue == 0) {
                                isDefaultValue = 0;
                                value = defaultValue;
                                log.info("提取类型={}，提取表达式={} 为空，使用默认值={}", "response-json", expression, value);
                            } else {
                                status = 1;
                                errorMsg = String.format("response cache error, json-path extract content is null, " +
                                        "expression[%s], processor=[%s], case=[%s]", expression, name, interfaceCaseId);
                                log.error(errorMsg);
                            }
                        } else {
                            isDefaultValue = 1;
                            if (jsonPathArray.size() == 1) {
                                Object o = jsonPathArray.get(0);
                                value = o == null ? null : o.toString();
                            } else {
                                value = JSON.toJSONString(jsonPathArray);
                            }
                            log.info("提取类型={}，提取表达式={}，写入缓存内容={}", "response-json", expression, value);
                        }
                    } else if (type == 1) { // xml
                        String s = "[]";
                        try {
                            s = ParseUtil.parseXml(responseBody, expression);
                        } catch (ParseException e) {
                            isThrowException = true;
                            exceptionMsg = e.getMessage();
                        }
                        ArrayList xpathArray = JSONObject.parseObject(s, ArrayList.class);
                        if (xpathArray.isEmpty()) {
                            if (haveDefaultValue == 0) {
                                isDefaultValue = 0;
                                value = defaultValue;
                                log.info("提取类型={}，提取表达式={} 为空，使用默认值={}", "response-xml", expression, value);
                            } else {
                                status = 1;
                                errorMsg = String.format("response cache error, xpath extract content is null, " +
                                        "expression[%s], processor=[%s], case=[%s]", expression, name, interfaceCaseId);
                                log.error(errorMsg);
                            }
                        } else {
                            isDefaultValue = 1;
                            if (xpathArray.size() == 1) {
                                Object o = xpathArray.get(0);
                                value = o == null ? null : o.toString();
                            } else {
                                value = JSON.toJSONString(xpathArray);
                            }
                            log.info("提取类型={}，提取表达式={}，写入缓存内容={}", "response-xml", expression, value);
                        }
                    } else if (type == 2) { //header
                        String s = "[]";
                        try {
                            s = ParseUtil.parseJson(responseHeaders, expression);
                        } catch (ParseException e) {
                            isThrowException = true;
                            exceptionMsg = e.getMessage();
                        }
                        ArrayList headerArray = JSONObject.parseObject(s, ArrayList.class);
                        if (headerArray == null || headerArray.isEmpty()) {
                            if (haveDefaultValue == 0) {
                                isDefaultValue = 0;
                                value = defaultValue;
                                log.info("提取类型={}，提取表达式={} 为空，使用默认值={}", "header", expression, value);
                            } else {
                                status = 1;
                                errorMsg = String.format("response cache error, headers json-path extract content is null, " +
                                        "expression[%s], processor=[%s], case=[%s]", expression, name, interfaceCaseId);
                                log.error(errorMsg);
                            }
                        } else {
                            isDefaultValue = 1;
                            if (headerArray.size() == 1) {
                                Object o = headerArray.get(0);
                                value = o == null ? null : o.toString();
                                JSONArray var1 = JSON.parseArray(value);
                                if (var1 == null) {
                                    value = null;
                                } else {
                                    if (var1.size() == 1) {
                                        Object var2 = var1.get(0);
                                        value = var2 == null ? null : var2.toString();
                                    } else {
                                        value = JSON.toJSONString(var1);
                                    }
                                }
                            } else {
                                value = JSON.toJSONString(headerArray);
                            }
                        }
                    } else if (type >= 7) {
                        status = 1;
                        log.error("not supported the processor type");
                        errorMsg = "not supported the processor type";
                    }

                    if (type <= 2) {
                        interfaceProcessorLog = new InterfaceProcessorLog();
                        interfaceProcessorLog.setProcessorId(processorDO.getId());
                        interfaceProcessorLog.setCaseId(processorDO.getCaseId());
                        interfaceProcessorLog.setCaseExecuteLogId(executedLogId);
                        interfaceProcessorLog.setName(name);
                        interfaceProcessorLog.setType(type);
                        interfaceProcessorLog.setExpression(expression);
                        if (!isThrowException) {
                            // 写入处理器记录表
                            interfaceProcessorLog.setIsDefaultValue(isDefaultValue);
                            interfaceProcessorLog.setValue(value);
                            interfaceProcessorLog.setCreatedTime(new Date());
                            interfaceProcessorLog.setStatus(status);
                            interfaceProcessorLog.setWr(1);
                            if (status == 0) {
                                interfaceProcessorLog.setErrorMsg(null);
                            } else{
                                interfaceProcessorLog.setErrorMsg(errorMsg);
                            }
                            // 写入处理器日志表
                            long start = TimeUtil.now();
                            interfaceProcessorLogService.saveInterfaceProcessorLog(interfaceProcessorLog);
                            RelyType relyType; // 0response-json/1response-html/2response-header
                            if (type == 0) {
                                relyType = RelyType.WRITE_PROCESSOR_RESPONSE_JSON;
                            } else if (type == 1) {
                                relyType = RelyType.WRITE_PROCESSOR_RESPONSE_HTML;
                            } else {
                                relyType = RelyType.WRITE_PROCESSOR_RESPONSE_HEADER;
                            }
                            log.info("写入处理器日志表");
                            // 如果处理器出错，那么将用例执行状态重新置为错误
                            if (status == 1) {
                                InterfaceCaseExecuteLog afterPostProcessorLogDo = new InterfaceCaseExecuteLog();
                                afterPostProcessorLogDo.setId(executedLogId);
                                afterPostProcessorLogDo.setStatus( 2);
                                afterPostProcessorLogDo.setErrorMessage(errorMsg);
                                logService.modifyExecuteLog(afterPostProcessorLogDo);
                                log.info("处理器运行错误，主动将用例执行状态置为错误");
                            } else {
                                if (casePreNo != null) { //如果为前置用例，仅写入前置用例域，
                                    redisUtil.hashPut(casePreNo, name, value);
                                    log.info("写入处理器-前置用例域，key={}，hashKey={}，value={}", casePreNo, name, value);
                                } else {
                                    if (suiteLogDetailNo == null) { // 不存在则写入临时域
                                        redisUtil.hashPut(NoUtil.TEMP_POST_PROCESSOR_NO, name, value);
                                        log.info("写入处理器-临时域，key={}，hashKey={}，value={}", NoUtil.TEMP_POST_PROCESSOR_NO, name, value);
                                    } else { // 否则写入测试套件域
                                        redisUtil.hashPut(suiteLogDetailNo, name, value, 24*60*60);
                                        log.info("写入处理器-测试套件域，key={}，hashKey={}，value={}", suiteLogDetailNo, name, value);
                                    }
                                }
                            }
                            redisUtil.stackPush(chainNo, chainNode(relyType, null, name, value, TimeUtil.now()-start, expression));
                            // 手动写入，否则前置用例的跟踪链看不到
                            InterfaceCaseExecuteLog modifyChain = new InterfaceCaseExecuteLog();
                            modifyChain.setId(executedLogId);
                            modifyChain.setChain(JSON.toJSONString(redisUtil.stackGetAll(chainNo)));
                            logService.modifyExecuteLog(modifyChain);
                        } else { // 若解析json、xpath出错
                            // 写入处理器记录表
                            interfaceProcessorLog.setIsDefaultValue(null);
                            interfaceProcessorLog.setValue(null);
                            interfaceProcessorLog.setCreatedTime(new Date());
                            interfaceProcessorLog.setStatus(1);
                            interfaceProcessorLog.setErrorMsg(exceptionMsg);
                            interfaceProcessorLogService.saveInterfaceProcessorLog(interfaceProcessorLog);
                            log.error("处理器解析出错，写入处理器记录表");
                            // 重置用例状态
                            InterfaceCaseExecuteLog afterPostProcessorLogDo = new InterfaceCaseExecuteLog();
                            afterPostProcessorLogDo.setId(executedLogId);
                            afterPostProcessorLogDo.setStatus(2);
                            afterPostProcessorLogDo.setErrorMessage(exceptionMsg);
                            logService.modifyExecuteLog(afterPostProcessorLogDo);
                            log.info("处理器解析出错，主动将用例执行状态置为错误");
                        }
                    }
                }
            }
        }
    }

    private Long onRequestError(Long interfaceCaseId, String url, String desc, Integer method,
                                   HashMap headersMap, HashMap paramsMap, String requestBody,
                                   String rawHeaders, String rawParams, String rawBody,
                                   String executor, String exceptionMessage, Long runTime,
                                   String suiteLogNo, String suiteLogDetailNo, Integer isFailedRetry,
                                   Integer source, String rawType, Integer bodyType, String chainNo){
        // 写入日志表
        InterfaceCaseExecuteLog executeLog = new InterfaceCaseExecuteLog();
        executeLog.setCaseId(interfaceCaseId);
        executeLog.setCaseDesc(desc);
        executeLog.setCaseMethod( method);
        // 避免重复序列化，统一处理 null 情况
       String requestHeadersJson = headersMap == null ? "": JSON.toJSONString(headersMap, JSONWriter.Feature.PrettyFormat);
       String requestParamsJson = paramsMap == null ? "": JSON.toJSONString(paramsMap, JSONWriter.Feature.PrettyFormat);

       executeLog.setRequestHeaders(requestHeadersJson);
       executeLog.setRequestParams(requestParamsJson);
       executeLog.setRequestBody(requestBody);
       executeLog.setRawRequestHeaders(rawHeaders);
       executeLog.setRawRequestParams(rawParams);
       executeLog.setRawRequestBody(rawBody);
       executeLog.setResponseCode( null);
       executeLog.setResponseHeaders(null);
       executeLog.setResponseBody(null);
       executeLog.setExecuter(executor);
       executeLog.setStatus(2);
       executeLog.setCreatedTime(new Date());
       executeLog.setErrorMessage(exceptionMessage);
       executeLog.setRunTime(runTime);
       executeLog.setCaseUrl( url);
       executeLog.setSuiteLogNo(suiteLogNo);
       executeLog.setSuiteLogDetailNo(suiteLogDetailNo);
       executeLog.setIsFailedRetry(isFailedRetry);
       executeLog.setSource(source);
       executeLog.setRawType(rawType);
       executeLog.setBodyType(bodyType);
       InterfaceCaseExecuteLog saveExecuteLog = interfaceCaseExecuteLogService.saveExecuteLog(executeLog);
       // 将调用链信息序列化保存
        Long executeLogId = saveExecuteLog.getId();
        InterfaceCaseExecuteLog updateChain = new InterfaceCaseExecuteLog();
        updateChain.setId(executeLogId);
        updateChain.setChain(JSON.toJSONString(redisUtil.stackGetAll(chainNo)));
        interfaceCaseExecuteLogService.modifyExecuteLog(updateChain);
        log.error("执行结束 ：{}  执行错误 {}, 错误日志Id {}",interfaceCaseId, executeLog,executeLogId);
        return executeLogId;
    }

    /**
     * 执行用例的全部断言
     * @param asserts 断言列表
     * @param interfaceCaseId 测试用例编号
     * @param executedLogId 此次执行日志编号
     * @param responseCode 响应状态码
     * @param responseHeaders 响应头
     * @param responseBody 响应体
     * @param runTime 执行耗时
     * @param chainNo 调用链路跟踪 将调用链信息序列化
     * @param suiteId 测试套件编号
     * @param isFailedRetry 记录此次是否为失败重跑
     * @param suiteLogDetailNo suiteLogNo仅记录重跑和真正运行的，suiteLogDetailNo会包括用例所依赖的case
     * @param casePreNo 前置用例的参数缓存用的key，为了防止异步执行用例时，tempPostProcessor key被覆盖， 仅前置用例执行时，需要该参数
     * @param globalHeaders 测试套件的headers
     * @param globalParams 测试套件的params
     * @param globalData 测试套件的data
     * @return 根据断言列表中的每次断言结果判定最终断言结果并返回
     */
    private Integer doAssert(List<InterfaceAssertVO> asserts, Long interfaceCaseId, Long executedLogId,
                          Integer responseCode, String responseHeaders, String responseBody, Long runTime,
                          String chainNo, Long suiteId, Integer isFailedRetry, String suiteLogDetailNo, String casePreNo,
                          HashMap globalHeaders, HashMap globalParams, HashMap globalData) {

        List<Integer> statusList = new ArrayList<>(); // 用来接收用例每个断言的结果

        for (InterfaceAssertVO interfaceAssertVO : asserts) {
            Integer assertStatus; // 是否通过 0通过 1失败 2错误
            String assertErrorMessage = null;

            Long assertId = interfaceAssertVO.getId();
            String assertName = interfaceAssertVO.getAssertName();
            Integer type = interfaceAssertVO.getType();
            String expression = interfaceAssertVO.getExpression();
            Integer operator = interfaceAssertVO.getOperator();
            Integer order = interfaceAssertVO.getOrder();

            // 断言基本信息
            InterfaceAssertLog assertLogDO = new InterfaceAssertLog();
            assertLogDO.setExecuteLogId(executedLogId);
            assertLogDO.setCaseId(interfaceCaseId);
            assertLogDO.setAssertName(assertName);
            assertLogDO.setAssertId(assertId);
            assertLogDO.setType(type);
            assertLogDO.setExpression(expression);
            assertLogDO.setOperator(operator);
            String exceptedResult = interfaceAssertVO.getExceptedResult();
            assertLogDO.setRawExceptedResult(exceptedResult);

            // 当断言出错
            if (null != exceptedResult) {
                try {
                    log.info("start parsing assertion expected results");
                    exceptedResult = parser.parseDependency(exceptedResult, chainNo, suiteId, isFailedRetry, suiteLogDetailNo, globalHeaders, globalParams, globalData, casePreNo);
                    log.info("complete the analysis of the expected results, expected results [{}]", exceptedResult);
                } catch (ParseException   | SQLException | ClassNotFoundException e) {
                    assertErrorMessage = e.getMessage();
                    assertStatus = 2;
                    statusList.add(assertStatus); // 将每次断言status都加入集合
                    assertLogDO.setExceptedResult(exceptedResult);
                    assertLogDO.setOrder(order);
                    assertLogDO.setActualResult(null);
                    assertLogDO.setStatus(assertStatus);
                    assertLogDO.setErrorMessage(assertErrorMessage);
                    assertLogDO.setCreatedTime(new Date());
                    log.error("error in parsing assert's expected results process");
                    assertLogService.saveInterfaceAssertLog(assertLogDO);
                    continue;
                }
            }

            // 执行断言
            assertLogDO.setExceptedResult(exceptedResult);
            assertLogDO.setOrder(order);
            String actualResult = null;
            ArrayList resultList = null;
            boolean isPass;
            try {
                if (type == 0) { // json
                    actualResult = ParseUtil.parseJson(responseBody, expression);
                    log.info("actual results={}, assert type={}, body={}, expression={}", actualResult, "json-path", responseBody, expression);
                    resultList = JSONObject.parseObject(actualResult, ArrayList.class);
                } else if (type == 1) { // html
                    actualResult = ParseUtil.parseXml(responseBody, expression);
                    log.info("actual results={}, assert type={}, body={}, expression={}", actualResult, "xpath", responseBody, expression);
                    resultList = JSONObject.parseObject(actualResult, ArrayList.class);
                } else if (type == 2) { // header
                    actualResult = ParseUtil.parseJson(responseHeaders, expression);
                    log.info("actual results={}, assert type={}, header={}, expression={}", actualResult, "json-path", responseHeaders, expression);
                    resultList = JSONObject.parseObject(actualResult, ArrayList.class);
                } else if (type == 3) { // responseCode
                    actualResult = String.valueOf(responseCode);
                    log.info("actual results={}, assert type={}, code={}, expression={}", actualResult, "code", responseCode, expression);
                } else if (type == 4) { // runtime
                    actualResult = String.valueOf(runTime);
                    log.info("actual results={}, assert type={}, runtime={}, expression={}", actualResult, "runtime", actualResult, expression);
                } else {
                    throw new ValidUtilException("not supported assert type");
                }
                log.info("预期结果={}", exceptedResult);
                log.info("操作符={}", operator);
                log.info("实际结果={}", actualResult);

                if (type < 3) { // 0json/1html/2header/3responseCode/4runtime
                    if (resultList.size() == 1) {
                        Object o = resultList.get(0);
                        actualResult = o == null ? null : o.toString();
                        if (type == 2) {
                            JSONArray var1 = JSON.parseArray(actualResult);
                            if (var1 == null) {
                                actualResult = null;
                            } else {
                                if (var1.size() == 1) {
                                    Object var2 = var1.get(0);
                                    actualResult = var2 == null ? null : var2.toString();
                                } else {
                                    actualResult = JSON.toJSONString(var1);
                                }
                            }
                        }
                    } else {
                        actualResult = JSON.toJSONString(resultList);
                    }
                }
                isPass = AssertUtil.asserts(actualResult, operator, exceptedResult);
                if (isPass) {
                    log.info("assertion success");
                    assertStatus = 0;
                } else {
                    log.warn("assertion failure");
                    assertStatus = 1;
                }
            } catch (Exception e) {
                assertStatus = 2;
                log.error("assertion failure, errorMsg={}", e.getMessage());
                assertErrorMessage = e.getMessage();
            }
            assertLogDO.setActualResult(actualResult);
            assertLogDO.setStatus(assertStatus);
            statusList.add(assertStatus); // 将每次断言status都加入集合
            assertLogDO.setErrorMessage(assertErrorMessage);
            assertLogDO.setCreatedTime(new Date());
            assertLogService.saveInterfaceAssertLog(assertLogDO);
        }

        // 根据断言结果调整用例的执行结果
        InterfaceCaseExecuteLog updateStatus = new InterfaceCaseExecuteLog();
        updateStatus.setId(executedLogId);
        if (statusList.contains( 2)) {
            updateStatus.setStatus( 2);
        } else {
            if (!statusList.contains( 1)) {
                updateStatus.setStatus( 0);
            } else {
                updateStatus.setStatus( 1);
            }
        }
        logService.modifyExecuteLog(updateStatus);

        // 修改调用链
        InterfaceCaseExecuteLog updateChain = new InterfaceCaseExecuteLog();
        updateChain.setId(executedLogId);
        updateChain.setChain(JSON.toJSONString(redisUtil.stackGetAll(chainNo)));
        logService.modifyExecuteLog(updateChain);

        // 返回用例执行断言后的状态
        return updateStatus.getStatus();
    }

    /**
     * 将测试套件中的header、params、form-data-encoded合并到请求信息中
     * @param suiteProperty 测试套件中的属性
     * @param kv 测试用例的属性
     * @return 合并后的属性
     */
    private HashMap mergeSuiteProperty(HashMap suiteProperty, String kv) {
        HashMap property = JSONObject.parseObject(kv, HashMap.class);
        if (suiteProperty != null) {
            if (property != null) {
                suiteProperty.putAll(property);
            }
            return suiteProperty;
        } else {
            return property;
        }
    }

    /**
     * 将数据库中的method字段映射HttpMethod枚举
     * @param methodByte 数据库中的method字段
     * @return HttpMethod枚举
     */
    public HttpMethod httpMethod(Integer methodByte)  {
        if (methodByte == 0) {
            return HttpMethod.GET;
        } else if (methodByte == 1) {
            return HttpMethod.POST;
        } else if (methodByte == 2) {
            return HttpMethod.PATCH;
        } else if (methodByte == 3) {
            return HttpMethod.PUT;
        } else if (methodByte == 4) {
            return HttpMethod.DELETE;
        } else if (methodByte == 5) {
            return HttpMethod.HEAD;
        } else if (methodByte == 6) {
            return HttpMethod.OPTIONS;
        } else if (methodByte == 7) {
            return HttpMethod.TRACE;
        } else {
            log.error("不支持http方法");
            throw new ValidUtilException("不支持http方法");
        }
    }

    /**
     * 根据bodyType，确定执行日志中的rawBody
     * @param bodyType bodyType
     * @return 执行日志中记录的rawBody
     */
    private String logRawBody(Integer bodyType,String formData,String formDataEncoded,String raw){

        if (bodyType == null){
            throw new ValidUtilException("bodyType不能为空");
        }

        return switch (bodyType) {
            case 0 ->// from-data
                    formData;
            case 1 -> // x-www-form-encoded
                    formDataEncoded;
            case 2 -> // raw
                    raw;
            case 9 -> // none
                    null;
            default -> throw new ValidUtilException("bodyType参数错误");
        };
    }

    /**
     * 根据bodyType，确定执行日志中的requestBody
     * @param bodyType bodyType
     * @return 执行日志中记录的requestBody
     */
    private String logRequestBody(Integer bodyType, HashMap formDataMap, HashMap formDataEncodedMap, String raw){
        if (bodyType == null){
            throw new ValidUtilException("bodyType不能为空");
        }
        return switch (bodyType) {
            case 0 ->// from-data
                    JSON.toJSONString(formDataMap, JSONWriter.Feature.PrettyFormat);
            case 1 -> // x-www-form-encoded
                    JSON.toJSONString(formDataEncodedMap, JSONWriter.Feature.PrettyFormat);
            case 2 -> // raw
                    raw;
            case 9 -> // none
                    null;
            default -> throw new ValidUtilException("bodyType参数错误");
        };
    }




    /**
     * 将前端包含name、value、checked、value的对象数组转成对象
     * @param text  header、param、form、formEncoded
     * @return 转换后的
     */
    public String kvCast(String text) {
        if (text == null || text.isEmpty()) {
            return null;
        }

        try {
            JSONArray array = JSON.parseArray(text);
            if (array == null || array.isEmpty()) {
                return null;
            }

            JSONObject object = new JSONObject();
            array.forEach(item -> {
                if (item instanceof JSONObject) {
                    JSONObject jsonObject = (JSONObject) item;
                    String name = jsonObject.getString("name");
                    String value = jsonObject.getString("value");
                    boolean checked = jsonObject.getBooleanValue("checked");
                    if (checked) {
                        object.put(name, value);
                    }
                }
            });
            return JSON.toJSONString(object);
        } catch (Exception e) {
            throw new ValidUtilException("headers/params/form-data/form-data-encoded syntax error");
        }
    }
}
